package com.ndood.reconciliation.app.redis;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * https://blog.csdn.net/abbc7758521/article/details/77990048
 * https://www.cnblogs.com/linjiqin/p/8003838.html
 */
@Component
@Slf4j
public class ReconRedisTool {
	private static final Integer LOCK_TIMEOUT = 120 * 1000;

	@Autowired
	private JedisPool jedisPool;

	private static final int BATCH_COUNT = 1000;

	/**
	 * 1 从缓存队列中获取一个key
	 */
	public Optional<String> spopKeyFromSnapchat() {
		Jedis jedis = jedisPool.getResource();
		Optional<String> option = Optional.ofNullable(jedis.spop(RedisReconKeyHelper.KEY_STORE_SNAPCHAT));
		jedis.close();
		return option;
	}

	/**
	 * 2 外部调用加锁的方法
	 */
	public boolean tryLock(String lockKey, Long timeout) {
		Jedis jedis = jedisPool.getResource();
		try {
			Long currentTime = System.currentTimeMillis();// 开始加锁的时间
			boolean result = false;

			while (true) {
				if ((System.currentTimeMillis() - currentTime) / 1000 > timeout) {// 当前时间超过了设定的超时时间
					log.info("Execute DistributedLockHandler.tryLock method, Time out.");
					break;
				} else {
					result = innerTryLock(lockKey);
					if (result) {
						break;
					} else {
						log.info("Try to get the Lock,and wait 100 millisecond....");
						Thread.sleep(100);
					}
				}
			}
			return result;

		} catch (Exception e) {
			log.info("Failed to run DistributedLockHandler.getLock method." + e);
			return false;

		} finally {
			jedis.close();

		}
	}

	/**
	 * 3 释放锁
	 */
	public void realseLock(String lockKey) {
		Jedis jedis = jedisPool.getResource();
		if (!checkIfLockTimeout(System.currentTimeMillis(), lockKey)) {
			jedis.del(lockKey);
		}
		jedis.close();
	}

	/**
	 * 4 内部获取锁的实现方法
	 */
	private boolean innerTryLock(String lockKey) {
		Jedis jedis = jedisPool.getResource();
		try {
			long currentTime = System.currentTimeMillis();// 当前时间
			String lockTimeDuration = String.valueOf(currentTime + LOCK_TIMEOUT + 1);// 锁的持续时间
			Long result = jedis.setnx(lockKey, lockTimeDuration);
			if (result == 1) {
				return true;
			} else {
				if (checkIfLockTimeout(currentTime, lockKey)) {
					String preLockTimeDuration = jedis.getSet(lockKey, lockTimeDuration);
					if (currentTime > Long.valueOf(preLockTimeDuration)) {
						return true;
					}
				}
				return false;
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * 5 判断加锁是否超时
	 */
	private boolean checkIfLockTimeout(Long currentTime, String lockKey) {
		Jedis jedis = jedisPool.getResource();
		try {
			if (currentTime > Long.valueOf(jedis.get(lockKey))) {// 当前时间超过锁的持续时间
				return true;
			} else {
				return false;
			}
		} finally {
			jedis.close();
		}
	}

	public void saddKey(String key) {
		Jedis jedis = jedisPool.getResource();
		jedis.sadd(RedisReconKeyHelper.KEY_STORE, key);
		jedis.close();
	}

	public void createSnapchat() {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.renamenx(RedisReconKeyHelper.KEY_STORE, RedisReconKeyHelper.KEY_STORE_SNAPCHAT);
		} catch (Exception ignored) {
		}
		jedis.close();
	}

	/**
	 * 从队列中获取订单
	 */
	@Deprecated
	public List<String> getOrders(String reconKey) {
		Jedis jedis = jedisPool.getResource();
		List<String> recons = jedis.lrange(reconKey, 0, BATCH_COUNT - 1);
		if (recons != null && recons.size() > 0) {
			jedis.ltrim(reconKey, recons.size(), -1);
		}
		if (recons.size() == BATCH_COUNT ) {
			Long leftCount = jedis.llen(reconKey);
			log.info("getRecon reconKey:{} leftCount:{}", reconKey, leftCount);
		}
		jedis.close();
		return recons;
	}
	
}